package com.duowan.cms.service.article;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.ibatis.type.Alias;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.duowan.cms.common.domain.Page;
import com.duowan.cms.common.exception.BaseCheckedException;
import com.duowan.cms.common.service.DoToDtoConvertorFactory;
import com.duowan.cms.common.util.DateUtil;
import com.duowan.cms.common.util.IdManager;
import com.duowan.cms.common.util.LogUtil;
import com.duowan.cms.common.util.PathUtil;
import com.duowan.cms.common.util.StringUtil;
import com.duowan.cms.common.util.ThreadUtil;
import com.duowan.cms.core.rmi.client.article.ArticleRemoteService;
import com.duowan.cms.domain.article.Article;
import com.duowan.cms.domain.article.Article4TagList;
import com.duowan.cms.domain.article.ArticleGameLib;
import com.duowan.cms.domain.article.rpst.Article4TagListRepository;
import com.duowan.cms.domain.article.rpst.ArticleGameLibRepository;
import com.duowan.cms.domain.article.rpst.ArticleRepository;
import com.duowan.cms.dto.article.Article4TagListInfo;
import com.duowan.cms.dto.article.Article4TagListSearchCriteria;
import com.duowan.cms.dto.article.ArticleInfo;
import com.duowan.cms.dto.article.ArticleSearchCriteria;
import com.duowan.cms.dto.article.ArticleStatus;
import com.duowan.cms.dto.article.SimpleArticleInfo;
import com.duowan.cms.dto.channel.ChannelInfo;
import com.duowan.cms.dto.user.UserInfo;
import com.duowan.cms.parser.rmi.client.template.TemplateParserRemoteService;
import com.duowan.cms.service.article.util.ArticleImageDealer;
import com.duowan.cms.service.article.util.ArticlePublisher;
import com.duowan.cms.service.channel.ChannelService;
import com.duowan.cms.service.tag.TagService;

@Service("articleService")
@Alias("articleRemoteService")
public class ArticleServiceImpl implements ArticleService, ArticleRemoteService {

    @Autowired
    private ArticleRepository articleRepository;

    @Autowired
    private Article4TagListRepository article4TagListRepository;

    @Autowired
    private ArticleGameLibRepository articleGameLibRepository;

    @Autowired
    private ChannelService channelService;
    @Autowired
    private TagService tagService;

    @Autowired
    private Article4TagListService article4TagListService;

    @Autowired
    private TemplateParserRemoteService parserRemoteService;

    private static Logger logger = Logger.getLogger(ArticleService.class);

    @Override
    public List<ArticleInfo> getPrepublishArticle() {
        List<ArticleInfo> prepublishArticleList = new ArrayList<ArticleInfo>();
        List<ChannelInfo> channelInfoList = channelService.getAllChannel();
        //String channelIds = PropertiesHolder.get("prepublishChannelids"); // 目前做预定发布器的
        for (ChannelInfo channelInfo : channelInfoList) {
//            if (channelIds.indexOf("," + channelInfo.getId().toLowerCase() + ",") > -1) {
//               
//            }
            ArticleSearchCriteria searchCriteria = new ArticleSearchCriteria();
            searchCriteria.addStatus(ArticleStatus.PER_PUBLISH);
            searchCriteria.setPageSize(null);
            searchCriteria.setPrePublishTimeEnd(new Date());
            searchCriteria.setChannelId(channelInfo.getId());
            prepublishArticleList.addAll(articleRepository.listSearch(searchCriteria));

        }
        return prepublishArticleList;
    }
    
    @Override
    public void handlePrepublishEmptyLink() throws BaseCheckedException {
        // TODO Auto-generated method stub
        List<Article4TagListInfo> list = getPrepublishEmpty();
        logger.info("处理预发布空链接，数量：" + list.size());
        updatePrepublishEmptyLink(list);
    }
    
    private List<Article4TagListInfo> getPrepublishEmpty() {
        List<Article4TagListInfo> prepublishArticleList = new ArrayList<Article4TagListInfo>();
        List<ChannelInfo> channelInfoList = channelService.getAllChannel();
        Date d = new Date();
        for (ChannelInfo channelInfo : channelInfoList) {
            Article4TagListSearchCriteria searchCriteria = new Article4TagListSearchCriteria();
            searchCriteria.setStatus(Article4TagList.EMPTYLINK_PRE);
            searchCriteria.setPageSize(null);
            searchCriteria.setChannelId(channelInfo.getId());
            searchCriteria.setPublishTimeEnd(d);
            prepublishArticleList.addAll(article4TagListRepository.listSearch(searchCriteria));
        }
        return prepublishArticleList;
    }
    private void updatePrepublishEmptyLink(List<Article4TagListInfo> list) throws BaseCheckedException {
        for(Article4TagListInfo a : list){
            a.setStatus(Article4TagList.EMPTYLINK_NORMAL);
            article4TagListRepository.update(new Article4TagList(a));
        }
    }
    

    @Override
    public List<ArticleInfo> getRecentUpdateArticle(String channelId, int minute) {
        ArticleSearchCriteria searchCriteria = new ArticleSearchCriteria();
        searchCriteria.setPageSize(null);
        searchCriteria.setUpdateTimeStart(DateUtil.getBeforeTime(minute));
        searchCriteria.setChannelId(channelId);
        return articleRepository.listSearch(searchCriteria);
    }

    @Override
    public void updatePower(String channelId, Long articleId, int power) {
        Article article = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        article.setPower(power);
        articleRepository.update(article);
        logger.info("更新文章[channelId=" + channelId + ", articleId=" + articleId + "]文章的权限值为" + power);
    }

    /**
     * 检查文章的标题是否已经存在
     * @param channelId
     * @param articleId 为空时，只判断数据库是否存在；不为空时，需要比较ID；
     * @param title
     */
    @Override
    public boolean checkTitleIsExisted(String channelId, String articleId, String title) {
        Article article = articleRepository.getByTitle(channelId, title);
        if (article == null)
            return false;
        if (ArticleStatus.DELETED == article.getStatus()) {
            return false;
        }
        if (StringUtil.isEmpty(articleId)) {
            return true;
        } else {
            if (Long.parseLong(articleId) == article.getId()) {
                return false;
            } else {
                return true;
            }
        }
    }

    @Override
    public void updateDayNum(String channelId, Long articleId, int num) {
        Article article = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        article.setDayNum(article.getDayNum() + num);
        articleRepository.update(article);
        logger.info("设置文章[channelId=" + channelId + ", articleId=" + articleId + "]天数为" + num);
    }

    @Override
    public void resetDayNum(String channelId, Long articleId) {
        Article article = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        article.resetDayNum();
        articleRepository.update(article);
        logger.info("重置文章[channelId=" + channelId + ", articleId=" + articleId + "]天数");
    }

    @Override
    public void publishEmptyLink(String channelId, List<Article4TagListInfo> article4TagListInfoList) throws BaseCheckedException {
        List<Article4TagList> list = new ArrayList<Article4TagList>();
        for (int i = 0; i < article4TagListInfoList.size(); i++) {
            list.add(new Article4TagList(article4TagListInfoList.get(i)));
        }

        article4TagListRepository.saveList(channelId, list);
        ArticlePublisher articlePublisher = ArticlePublisher.getInstance();
        articlePublisher.GenerateEmptyLinkFile(article4TagListInfoList.get(0));
    }

    /**
     * 文章发布(包括文章修改再发布)
     * 	1.只有"新增文章"或"修改预发布文章状态的文章" 页面才显示 <预发布时间> 选择项。
    	2.仅当预发布时间存在且在当前时间之后，文章才进行预发布处理。
    		其他情况都视作直接发布。
     */
    @Override
    public void publish(ArticleInfo articleInfo) throws BaseCheckedException {

        String channelId = articleInfo.getChannelInfo().getId();
        Long articleId = articleInfo.getId();

        // 1.预处理tags，去重复取得tagtree
        articleInfo.setTags(tagService.getTagTreeByPostTags(channelId, articleInfo.getTags()));
        if (!StringUtil.isEmpty(articleInfo.getPictureUrl())) {
            articleInfo.setTags(tagService.addTagStr(articleInfo.getTags(), "图片"));
        }
        // 2.预处理realtags
        articleInfo.setRealtags(tagService.getTagTreeByPostTagsExcludeSpecial(channelId, articleInfo.getTags()));
        // 3.预处理内容中的图片，异步实现抓取网络图片，删除没用的图片
        String content = new ArticleImageDealer().dealWithImgInContent(articleInfo);
        articleInfo.setContent(content);
        articleInfo.setUrlOnLine(PathUtil.getArticleOnlineUrl(articleInfo.getChannelInfo().getDomain(), articleId));

        //发布
        ArticlePublisher articlePublisher = ArticlePublisher.getInstance();
        if (articleInfo.getPrePublishTime() != null && articleInfo.getPrePublishTime().after(new Date())) {
            // 若发布时间大于当前时间，则为预定发布
            articlePublisher.reservePublish(articleInfo); // 预发布（未到时间，只是入库）
        } else {
            articlePublisher.immediatePublish(articleInfo); // 立即发布
        }
    }

    @Override
    public Page<ArticleInfo> pageSearch(ArticleSearchCriteria searchCriteria) {
        return articleRepository.pageSearch(searchCriteria);
    }

    @Override
    public Page<SimpleArticleInfo> pageSearch4Show(ArticleSearchCriteria searchCriteria) {
        return articleRepository.pageSearch4Show(searchCriteria);
    }

    @Override
    public ArticleInfo getByChannelIdAndArticleId(String channelId, Long articleId) {
        Article article = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        ArticleInfo articleInfo = (ArticleInfo) DoToDtoConvertorFactory.getConvertor(Article.class).do2Dto(article);
        // 设置相关游戏
        ArticleGameLib articleGameLib = articleGameLibRepository.getArticleGameLib(channelId, articleId);
        if (articleGameLib != null) {
            articleInfo.setRelateGame(articleGameLib.getRelategame());
        }
        return articleInfo;
    }

    /**
     * 1.从Article_表删除数据
     * 2.从List_表删除数据
     * 3.清空生成的HTML页面
     */
    @Override
    public void delete(UserInfo userInfo, String channelId, Long articleId) throws BaseCheckedException {
        Article article = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        article.setStatus(ArticleStatus.DELETED.getValue());
        article.setLastUpdateTime(new Date());
        article.setLastUpdateUserId(userInfo.getUserId());
        article.setLogs(LogUtil.getLogBeforeTen(userInfo.getUserId() + "于" + DateUtil.format(new Date(), DateUtil.exportXlsDateCreateTimeFormat) + "对文章进行彻底删除" + "<br>\n"
                + article.getLogs()));
        articleRepository.update(article);
        logger.info("用户[" + userInfo.getUserId() + "]把文章标题为[" + article.getTitle() + "][channelId=" + channelId + ",articleId=" + articleId + "]的文章状态更新为删除");
        final String channelIdFinal = channelId;
        final Long articleIdFinal = articleId;
        ThreadUtil.getThreadPool().execute(new Runnable() {
            public void run() {
                article4TagListRepository.logicDeleteByChannelIdAndArticleId(channelIdFinal, articleIdFinal);
                try {
                    parserRemoteService.cleanUpArticleFile(channelIdFinal, articleIdFinal);
                } catch (BaseCheckedException e) {
                    logger.error("清空生成的HTML页面出错:", e);
                }
            }
        });

        logger.info("文章[channelId=" + channelId + ", articleId=" + articleId + "]删除成功。");
    }

    /**
     *  1. 隐藏文章，
     *  2.清空文章文章静态页面
     *  3.删除文章列表数据
     */
    @Override
    public void hide(UserInfo userInfo, String channelId, Long articleId) throws ParseException, BaseCheckedException {
        // 隐藏文章
        Article article = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        article.setPrePublishTime(DateUtil.parse("3000-11-11 11:11:11", DateUtil.exportXlsDateCreateTimeFormat));
        article.setStatus(ArticleStatus.PER_PUBLISH.getValue());
        article.setLastUpdateTime(new Date());
        article.setLastUpdateUserId(userInfo.getUserId());
        article.setLogs(LogUtil.getLogBeforeTen(userInfo.getUserId() + "于" + DateUtil.format(new Date(), DateUtil.exportXlsDateCreateTimeFormat) + "对文章进行隐藏" + "<br>\n"
                + article.getLogs()));
        articleRepository.update(article);
        final String channelIdFinal = channelId;
        final Long articleIdFinal = articleId;
        ThreadUtil.getThreadPool().execute(new Runnable() {
            public void run() {
                try {
                    parserRemoteService.cleanUpArticleFile(channelIdFinal, articleIdFinal);
                } catch (BaseCheckedException e) {
                    logger.error("清空文章文章静态页面出错:", e);
                }
                article4TagListService.deleteByChannelIdAndArticleId(channelIdFinal, articleIdFinal);
            }
        });

        logger.info("文章[channelId=" + channelId + ", articleId=" + articleId + "]隐藏成功，并且清除静态页面。");
    }

    @Override
    public void updatePublishTime(String channelId, Long articleId, Date newPublishTime) throws BaseCheckedException {
        // 1.获取文章
        Article a = articleRepository.getByChannelIdAndArticleId(channelId, articleId);
        if (null == a)
            return;
        // 更新文章
        a.setPublishTime(newPublishTime);
        // 重新计算daynum
        int newDayNum = IdManager.id2DayNum(newPublishTime.getTime() - IdManager.BASE_TIMESTAMP);
        a.setDayNum(newDayNum);
        a.setLastUpdateTime(new Date());
        articleRepository.update(a);
        // 更新列表
        article4TagListRepository.updatePublishTime(channelId, articleId, newPublishTime, newDayNum);

    }

    @Override
    public List<ArticleInfo> listSearch(ArticleSearchCriteria searchCriteria) {
        return articleRepository.listSearch(searchCriteria);
    }

    @Override
    public String getArticleUrl(String channelId, Long articleId) {
        return PathUtil.getArticleOnlineUrl(channelService.getById(channelId).getDomain(), articleId);
    }

}
